#define _XOPEN_SOURCE

#include <sqlite3.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

int init_db(sqlite3 *db)
{
    int rc;
    char *err_msg = NULL;
    char *sql = "CREATE TABLE IF NOT EXISTS parking_record (\
                                \"id\"	INTEGER,\
                                \"plate_number\"	TEXT NOT NULL,\
                                \"vehicle_type\"	INTEGER NOT NULL,\
                                \"parking_time\"	TEXT NOT NULL,\
                                \"leaving_time\"	TEXT,\
                                PRIMARY KEY(\"id\" AUTOINCREMENT)\
                            );";

    rc = sqlite3_exec(db, sql, 0, 0, &err_msg);
    if (rc != SQLITE_OK)
    {
        fprintf(stderr, "SQL error: %s\n", err_msg);
        sqlite3_free(err_msg);
        return 1;
    }

    return 0;
}

time_t str2time(const char* from)
{
    //tm需要初始化为0，tm_isdst为随机值会导致mktime失败
    struct tm tm = {0};
    strptime(from, "%Y-%m-%d %H:%M:%S", &tm);
    return mktime(&tm);
}

char *time2str(time_t *from)
{
    time_t t = time(NULL);
    if (from)
    {
        t = *from;
    }
    struct tm tm = {0};
    localtime_r(&t, &tm);
    static char s[20];
    strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", &tm);
    return s;
}

int parking(sqlite3 *db, char *plate_number, int vehicle_type)
{
    char *now = time2str(NULL);
    char *sql = sqlite3_mprintf("INSERT INTO parking_record(plate_number, vehicle_type, "
                                "parking_time) VALUES('%q', '%d', '%q');",
                                plate_number, vehicle_type, now);
    char *err_msg = NULL;
    int rc = sqlite3_exec(db, sql, 0, 0, &err_msg);

    sqlite3_free(sql);

    if (rc != SQLITE_OK)
    {
        fprintf(stderr, "SQL error: %s\n", err_msg);
        sqlite3_free(err_msg);
        return 1;
    }

    return 0;
}

int get_entry_time_callback(void *data, int argc, char **argv, char **col_names)
{
    if (argc > 0 && argv[0] != NULL)
    {
        time_t *entry_time = (time_t *)data;
        *entry_time = str2time(argv[0]);
    }

    return 0;
}

int get_entry_time(sqlite3 *db, const char *plate_number, time_t *entry_time)
{
    char *sql = sqlite3_mprintf(
        "SELECT parking_time FROM parking_record WHERE plate_number='%q' AND leaving_time IS NULL;", plate_number);
    int rc = sqlite3_exec(db, sql, get_entry_time_callback, entry_time, NULL);
    sqlite3_free(sql);

    if (rc != SQLITE_OK)
    {
        fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
        return 1;
    }

    return 0;
}

int leaving(sqlite3 *db, char *plate_number)
{
    time_t entry_time = 0;
    int rc = get_entry_time(db, plate_number, &entry_time);

    if (rc != 0 || !entry_time)
    {
        fprintf(stderr, "Failed to get entry time\n");
        sqlite3_close(db);
        return 1;
    }

    time_t now = time(NULL);
    time_t parking_time = now - entry_time;

    char *leaving_time = time2str(&now);

    char *sql = sqlite3_mprintf("UPDATE parking_record SET leaving_time='%q' WHERE "
                                "plate_number='%q' AND leaving_time IS NULL;",
                                leaving_time, plate_number);
    char *err_msg = 0;
    rc = sqlite3_exec(db, sql, 0, 0, &err_msg);

    sqlite3_free(sql);

    if (rc != SQLITE_OK)
    {
        fprintf(stderr, "SQL error: %s\n", err_msg);
        sqlite3_free(err_msg);
        return 1;
    }

    printf("parking time: %ld min\n", parking_time / 60);

    return 0;
}

int main()
{
    sqlite3 *db;

    if (sqlite3_open("test.db", &db) != SQLITE_OK)
    {
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return 1;
    }

    init_db(db);

    parking(db, "陕AX216Z", 1);
    parking(db, "陕A8Y15C", 2);
    sleep(66);
    leaving(db, "陕AX216Z");
    leaving(db, "陕AX216Z");

    sqlite3_close(db);
    return 0;
}